﻿// owner 蒋家伟

#pragma once
#include <type_traits>
#include "WeakReference.h"

#ifdef _WINDOWS
#include <assert.h>
#endif

// 描述：WeakPtr不拥有对象的所有权，但是知道对象是否被析构
// 作用：防止野指针导致程序崩溃
// 用例：与常规指针使用没有区别
//      伪代码:
//           {
//                  class A : public WeakReference;
//                  void Test()
//                  {
//                      A* pA = new A;
//                      WeakPtr<A> wpA = pA;
//                      ....
//                      delete pA; // 此时pA被析构，如果其他地方缓存了pA，对pA操作则会出现野指针崩溃
//                                 // 如果对wpA进行判断，可以发现wpA为空指针。这样就可以通过if(wpA)不继续使用。
//                      // 也就是说不缓存裸指针，而采用WeakPtr作为成员变量缓存则更加安全
//                      
//                  }
//           }
// 注意：模板T需要继承于WeakReference类型，T不能传入class指针或者引用，直接放入类名即可，构造的时候需要保证传入的指针不能为野指针。

namespace jsdk
{
    template<typename T>
    class WeakPtr
    {
        static_assert(std::is_base_of<jsdk::WeakReference, T>::value, "T Need Inherits WeakReference");
        static_assert(!(std::is_pointer<T>::value || std::is_reference<T>::value), "T is not Ptr or Reference");
    public:
        WeakPtr(T* ptr = nullptr) {
            if (ptr)
            {
                m_pProxy = ptr->getProxy();
#ifdef _WINDOWS
                // 目标对象的代理应该是自动生成的，这里生成失败需要考虑为什么？
                assert(m_pProxy);
#else
                if (!m_pProxy) return;
#endif
                m_pProxy->ref();
            }
        }

        ~WeakPtr() {
            if (m_pProxy)
            {
                m_pProxy->unRef();
            }
        }

        WeakPtr(const WeakPtr<T>& wptr) {
            if (wptr && wptr->getProxy())
            {
                m_pProxy = wptr.m_pProxy;
                m_pProxy->ref();
            }
        }

        WeakPtr& operator=(const WeakPtr<T>& wptr)
        {
            if (m_pProxy == wptr.m_pProxy)
                return *this;

            if (m_pProxy)
                m_pProxy->unRef();

            if(this->m_pProxy = wptr.m_pProxy)
                this->m_pProxy->ref();

            return *this;
        }

        WeakPtr(WeakPtr<T>&& rwptr)
        {
            if (m_pProxy == rwptr.m_pProxy)
                return;

            if (m_pProxy)
                m_pProxy->unRef();

            this->m_pProxy = rwptr.m_pProxy;
            rwptr.m_pProxy = nullptr;
        }

        const T* get() const {
            return m_pProxy ? static_cast<T*>(m_pProxy->get()) : nullptr;
        }

        T* get() {
            return m_pProxy ? static_cast<T*>(m_pProxy->get()) : nullptr;
        }

        void reset(T* ptr = nullptr)
        {
            if (ptr == nullptr)
            {
                if (m_pProxy)
                {
                    m_pProxy->unRef();
                    m_pProxy = nullptr;
                }
            }
            else
            {
                if (m_pProxy == ptr->getProxy()) 
                    return;

                if (m_pProxy)
                    m_pProxy->unRef();

                m_pProxy = ptr->getProxy();
                m_pProxy->ref();
            }
        }

        bool isValid() const {
            return m_pProxy ? m_pProxy->isValid() : false;
        }

        operator bool () const{
            return isValid();
        }

        bool operator==(const WeakPtr<T>& wptr) const
        {
            // 这里方便常规 ptr == nullptr 与 nullptr == ptr写法

            if (wptr.m_pProxy == nullptr)
            {
                return !this->isValid();
            }
            else if(this->m_pProxy)
            {
                return !wptr.isValid();
            }

            // 如果都有代理对象则依赖代理对象
            return this->m_pProxy == wptr.m_pProxy;
        }

        bool operator!=(const WeakPtr<T>& wptr) const
        {
           return !(*this == wptr);
        }

        bool operator!() const
        {
            return !isValid();
        }

        T& operator*()
        {
            return *get();
        }

        const T& operator*() const
        {
            return *get();
        }

        const T* operator->() const {
            return get();
        }

        T* operator->() {
            return get();
        }

    private:
        jsdk::WeakReference::Proxy* m_pProxy = nullptr;
    };
}

